package update_grammar;

import exception.ExtraCharactersException;
import exception.IllegalCharacterSequenceException;
import exception.LessCharactersExeption;
import exception.NoRuleException;
import guard_grammar.Token;

import java.io.IOException;
import java.util.LinkedList;
import java.util.Stack;

/**
 * @author Zlatka Trajcheska, Marija Petkovska
 * @version 1.0 18.02.2013 
 * 
 * In this class we will construct parse table who will help to construct the parser 
 *  */

public class Parser {

	public Stack<String> stack;
	ListOfRules rules;
	ParseTable table = new ParseTable();
	public LinkedList<Token> tokens;
	LinkedList<String> allowedList = new LinkedList<String>();

	/** Constructor
	 */
	public Parser(String s) {

		update_grammar.TokenSplitting ts = new update_grammar.TokenSplitting(s);
		this.tokens = ts.getTokens();
		System.out.println("The tokens are: "+this.tokens);
		this.stack = new Stack<String>();
		
		rules = new ListOfRules();
		this.stack.add("EXPRESSION");

		allowedList.add("+");
		allowedList.add("-");
		allowedList.add(";");
		allowedList.add("=");
	}

	/**
	 * The method that validates the string. Includes the Token splitting too.
	 * 
	 * @throws IOException
	 * @throws IllegalCharacterSequenceException
	 * @throws LessCharactersExeption
	 * @throws NoRuleException
	 * @throws ExtraCharactersException
	 */
	public void parse() throws IOException, 
							      IllegalCharacterSequenceException, 
							      LessCharactersExeption, 
							      NoRuleException, ExtraCharactersException
	{
		if(this.tokens == null)
		{
			throw new IllegalCharacterSequenceException();
		}
		
		int counter = 0;
		while (!this.stack.isEmpty()) 
		{
			String s = (String) this.stack.peek();

			
			//System.out.println("Stek: "+stack.toString());
			//System.out.println("Tokens: "+tokens.get(counter));
			
			
			if (this.stack.peek().equals("e")) {
				this.stack.pop();
			}
			
			//*************** if on top of the stack we have nonterminal *************** 
			if (s.equals(s.toUpperCase()) && (!allowedList.contains(s))) 
			{
				//search for the rule from parse table

				String s1=this.stack.pop();
				int id_rule;
				
				if((counter == tokens.size() ) && (stack.size()==0))
				{
					
					id_rule = table.find(s1,"e");
					System.out.println("The parsing was successful!");
					System.out.println("Rule1 "+id_rule);
					return;
					
				}
				
				else if (counter < tokens.size())
				{
					 id_rule = table.find(s1,tokens.get(counter).getId());
					 System.out.println("Rule2 "+id_rule);
				}
				
				else
				{
					throw new LessCharactersExeption();
				}

				//if there is no such rule
				if (id_rule == 0) 
				{
					throw new NoRuleException();
				}
				
				//if there is a rule we replace the nonterminal with the right side
				LinkedList<String> str = rules.find(id_rule);
				for (int i = str.size() - 1; i >= 0; i--) 
				{
					this.stack.push(str.get(i));
				}

			}
			
			//*************** if on top of the stack we have terminal ***************
			else {
				
				try
				{
					//if the terminal and the token are the same
					if (tokens.get(counter).getId().equals(this.stack.peek()))
					{

						this.stack.pop();
						counter++;
					}
					else
					{
						throw new IllegalCharacterSequenceException();
					}
				}
				catch(Exception e)
				{
					throw new ExtraCharactersException();
				}

			}			
		}
		System.out.println("The parsing was successful!");
	}
}
